#include "atom.h"
#include "predicates.h"
#include "tuple.h"
#include "tree.h"

std::string Tuple::toString (int precedence, bool formatting) {
  std::string out;
  int tupleOp = tupleOperator ();

  for(std::vector<pNode>::iterator p = nodes.begin (); p < nodes.end (); p++) {
    if(p != nodes.begin ())
      out += ' ';
    if(formatting)
      out += (*p).node->display (tupleOp + 1);
    else
      out += (*p).node->dump (tupleOp + 1);
  }

  if(nodes.size () <= 1) // Need bracket enforcement to a tuple
    return '[' + out + ']';
  else if(precedence <= tupleOp)
    return out;
  else
    return '(' + out + ')';
}

pNode Tuple::replicate () {
  if(fixed)
    return this;

  for(std::vector<pNode>::iterator p = nodes.begin (); p < nodes.end (); p++) {
    pNode replicatedElement ((*p).node->replicate ());

    if(replicatedElement.node != (*p).node) { // Copy on write
      Tuple *ret = new Tuple;
      ret->nodes.reserve (nodes.size ());
      ret->nodes.insert (ret->nodes.begin (), nodes.begin (), p++);
      ret->nodes.push_back (replicatedElement);
      while(p < nodes.end ())
        ret->nodes.push_back ((*p++).node->replicate ());

      ret->fixed = true; // Nodes after replication are always fixed
      return ret;
    }
  }

  fixed = true;
  return this;
}

class isTuple : public OnceProver {
predicateName("is.tuple")

  bool proveOnce () {
    return typeid(*tuple->nodes[1].final ()) == typeid(Tuple);
  }

  Tuple *tuple;
  void set (Tuple &t, System&) {
    tuple = &t;
  }
};

ProverFactoryRegistrar<isTuple, Tuple::ID, 2> isTupleRegistrar;
